package com.cgx.controller;

import com.cgx.service.VersionLockService;
import org.I0Itec.zkclient.ZkClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import redis.clients.jedis.JedisCommands;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @author chenguanxin
 * @date 2020-08-27 22:49
 */
@Controller
public class VersionLockController {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ZkClient zkClient;

    @Autowired
    VersionLockService versionLockService;


    /*
    /**
     * @author chenguanxin
     * @date 2020-09-05 19:08
     * @param request
     * @return java.lang.Object
     *  测试redis分布式锁接口
     *  每秒吞吐量3318, 数据库插入记录290
     *  异常率0.91
    */
    @RequestMapping("/testRedisDistributedLock")
    @ResponseBody
    public Object testDistributedLock(HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        try {
            String id = request.getParameter("id");
            boolean lock = (boolean) redisTemplate.execute(
                    new RedisCallback<Boolean>() {
                        @Override
                        public Boolean doInRedis(RedisConnection connection)
                                throws RuntimeException {
                            JedisCommands jedisCommands = (JedisCommands)
                                    connection.getNativeConnection();
                            //  利用redis的SETNX 原子操作
                            return "OK".equals(jedisCommands.set("distributed_lock:distributed_lock_" + id, "true", "NX", "EX", 10));
                        }
                    });
            if (lock) {
                try {
                    //  增加值
                    versionLockService.testVersionLock(id);
                } catch (Exception e) {
                    e.printStackTrace();
                    Assert.isTrue(false, e.getMessage());
                } finally {
//                 释放分布式锁
                    redisTemplate.execute(new RedisCallback<Boolean>() {
                        @Override
                        public Boolean doInRedis(RedisConnection connection)
                                throws DataAccessException {
                            return ((JedisCommands)connection.getNativeConnection()).del("distributed_lock:distributed_lock_" + id) == 1;
                        }
                    });
                }
            } else {
                Assert.isTrue(false, "获取分布式锁失败");
            }
            result.put("code", 0);
            result.put("success", true);
            result.put("msg", "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
            result.put("code", 500);
            result.put("success", false);
            result.put("msg", e.getMessage());
        }
        return result;
    }

    /*
    /**
     * @author chenguanxin
     * @date 2020-09-05 19:10
     * @param request
     * @return java.lang.Object
     *  测试数据库版本锁接口
     *  每秒吞吐量1430, 数据库插入记录426
     *  异常率0.70
    */
    @RequestMapping("/testVersionLock")
    @ResponseBody
    public Object testVersionLock(HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        try {
            String id = request.getParameter("id");
            versionLockService.testVersionLock(id);
            result.put("code", 0);
            result.put("success", true);
            result.put("msg", "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
            result.put("code", 500);
            result.put("success", false);
            result.put("msg", e.getMessage());
        }
        return result;
    }

    /*
    /**
     * @author chenguanxin
     * @date 2020-09-05 21:51
     * @param request
     * @return java.lang.Object
     *  zookeeper分布式锁测试
     *  每秒吞吐量1325, 数据库插入记录167
     *  异常率0.87
    */
    @RequestMapping("/testZKDistributedLock")
    @ResponseBody
    public Object testZKDistributedLock(HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        try {
            String id = request.getParameter("id");
            // 获取zk分布式锁，如果为true代表获取锁成功
            boolean lock = zkTryLock("/distributed_lock_" + id);
            if (lock) {
                try {
                    //  增加值
                    versionLockService.testVersionLock(id);
                } catch (Exception e) {
                    e.printStackTrace();
                    Assert.isTrue(false, e.getMessage());
                } finally {
//                 释放分布式锁
                    zkClient.delete("/distributed_lock_" + id);
                }
            } else {
                Assert.isTrue(false, "获取分布式锁失败");
            }
            result.put("code", 0);
            result.put("success", true);
            result.put("msg", "操作成功");
        } catch (Exception e) {
            e.printStackTrace();
            result.put("code", 500);
            result.put("success", false);
            result.put("msg", e.getMessage());
        }
        return result;
    }

    private boolean zkTryLock(String path) {
        try {
            //  利用zookeeper不能创建已经存在的节点的特点
            zkClient.createEphemeral(path);
            // 创建成功
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            // 创建失败
            return false;
        }
    }
}
